package com.example.qxfw.shfx.Service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.dmgis.entity.*;
import com.dmgis.service.DmServiceConnector;
import com.dmgis.service.MapXML;
import com.example.qxfw.common.entity.layer.TownshipLayer;
import com.example.qxfw.common.entity.layer.VillagePointLayer;
import com.example.qxfw.common.entity.qx.Water;
import com.example.qxfw.common.entity.qx.WaterStation;
import com.example.qxfw.common.entity.zy.Flooded;
import com.example.qxfw.common.entity.zy.RiverBasin;
import com.example.qxfw.common.util.DmgisUtils;
import com.example.qxfw.qxxx.mapper.RiverBasinMapper;
import com.example.qxfw.qxxx.mapper.WaterMapper;
import com.example.qxfw.qxxx.mapper.WaterStationMapper;
import com.example.qxfw.shfx.Mapper.FloodedMapper;
import com.example.qxfw.shfx.Service.YmfxService;
import com.example.qxfw.shfx.dto.HamletsAndRoadsInfoDto;
import com.example.qxfw.shfx.entity.ColorAndPos;
import com.example.qxfw.yjqx.dto.DlfxDto;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.util.*;
import java.util.List;

@Service
public class YmfxServiceImpl implements YmfxService {
    @Value("${dmgis.ip}")
    private String dmgisIp;
    @Value("${dmgis.port}")
    private String dmgisPort;

    @Value("${dmgis.serName}")
    private String serverName;

    @Autowired
    private WaterStationMapper waterStationMapper;
    @Autowired
    private FloodedMapper floodedMapper;
    @Autowired
    private RiverBasinMapper riverBasinMapper;
    @Autowired
    private WaterMapper waterMapper;

    @Override
    public List<ColorAndPos> automatedAnalysis() {
        // 获取所有站点
        List<Flooded> floodedList = new ArrayList<>();
        floodedList = floodedMapper.selectList(new LambdaQueryWrapper<Flooded>()
                .select(Flooded::getStationname)
                .groupBy(Flooded::getStationname));
        // 获取水情表中的距离当前时间最近的实况水位数据
        List<Water> waters = new ArrayList<>();
        for (int i = 0; i < floodedList.size(); i++) {
            // 使用子查询获取分组中的最小 latestobservetime
            List<Water> groupWaters = waterMapper.groupWaters(floodedList.get(i).getStationname());
            // 添加分组中的第一个数据
            if (!groupWaters.isEmpty()) {
                waters.add(groupWaters.get(0));
            } else {
                try {
                    throw new Exception("水情表中无相关数据！！！");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        // 判断
        List<ColorAndPos> colorAndPosList = new ArrayList<>();
        for (Water water : waters) {
            colorAndPosList.add(judgment(water.getStationname(), water.getSmallscalewaterstatus()));
        }
        return colorAndPosList;
    }

    @Override
    public ColorAndPos manualAnalysis(String stationName, double value) {
        return judgment(stationName, value);
    }

    @Override
    public List<Flooded> getWaterLevelStation() {
        return floodedMapper.selectList(new LambdaQueryWrapper<Flooded>()
                .select(Flooded::getStationname)
                .groupBy(Flooded::getStationname));

    }

    @Override
    public Double[][] getZoning(String stationName) {
        WaterStation waterStation = waterStationMapper.selectOne(new LambdaQueryWrapper<WaterStation>()
                .select(WaterStation::getBsnm)
                .like(WaterStation::getStnm, stationName));
        RiverBasin riverBasin = riverBasinMapper.selectOne(new LambdaQueryWrapper<RiverBasin>()
                .select(RiverBasin::getCoordinate)
                .like(RiverBasin::getName, waterStation.getBsnm().trim()));
        Double[][] pos = null;
        if (riverBasin != null) {
            String[] split = riverBasin.getCoordinate().split(",");
            pos = new Double[split.length / 2][2];
            for (int i = 0; i < split.length; i += 2) {
                double x = Double.parseDouble(split[i]);
                double y = Double.parseDouble(split[i + 1]);
                pos[i / 2][0] = x;
                pos[i / 2][1] = y;
            }
        } else {
            try {
                throw new Exception("无流域数据！！");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return pos;
    }

    @Override
    public List<Flooded> waterLevelJudgment(String stationName) {
        return floodedMapper.selectList(new LambdaQueryWrapper<Flooded>()
                .eq(Flooded::getStationname, stationName));
    }

    @Override
    public String descriptionWaterLevel(String stationName, double value) {
        String info = "当前流域为：" + stationName + "，当前水位为：" + value;
        String message = null;
        ColorAndPos judgment = judgment(stationName, value);
        String color = judgment.getColor();
        if (color == map.get("可能性很大")) {
            message = "，启动可能性很大";
        } else if (color == map.get("可能性大")) {
            message = "，启动可能性大";
        } else if (color == map.get("可能性较大")) {
            message = "，启动可能性较大";
        } else if (color == map.get("未达警戒值")) {
            message = "。";
        }
        return info + message;
    }

    @Override
    public List<HamletsAndRoadsInfoDto> geographicAnalysis(DlfxDto dlfxDto) throws UnsupportedEncodingException {
        // 获取前端给到的点集并处理
        StringBuilder sb = new StringBuilder();
        for (List<Double> po : dlfxDto.getPos()) {
            DmMapPoint dmMapPoint = DmgisUtils.wgsToLbt(po.get(0), po.get(1));
            sb.append(dmMapPoint.getX()).append(" ").append(dmMapPoint.getY()).append(";");
        }
        sb.deleteCharAt(sb.length() - 1);

        // 设置连接服务的IP和端口
        DmServiceConnector conn = new DmServiceConnector(dmgisIp, dmgisPort);
        // 创建地图图层查询的参数信息
        DmFeatureMapService dmFeatureMapService = new DmFeatureMapService();
        // 要查询的地图图层的名称
        dmFeatureMapService.setStrLayerName(dlfxDto.getLayerName());
        // 地图图层查询的属性参数信息。
        DmFeatureParam dmFeatureParam = new DmFeatureParam();
        // 是否返回属性，值为 0 表示不返回，非 0 表示返回属性
        dmFeatureParam.setAttribute(1);
        // 是否有坐标，值为 0 表示没有坐标，非 0 表示有坐标。
        dmFeatureParam.setGeometry(1);
        // 返回记录最大数，用于限制查询返回的记录数量,默认为1，表示查询一条，0为查询所以
        dmFeatureParam.setFeatureLimit(0);
        dmFeatureMapService.setParam(dmFeatureParam);
        // 查询类型，表示查询的方式，1 表示 id 查询，2 表示索引查询，0 表示空间查询
        dmFeatureMapService.setType("0");
        // 查询条件，包括查询语句、查询矩形范围和查询多边形范围。
        DmSql dmSql = new DmSql();
        // 设置查询条件语句
        dmSql.setStrPos(sb.toString());
        // 获取查询条件
        dmFeatureMapService.setM_sql(dmSql);
        // 生成查询的 XML 请求字符串
        String xml = dmFeatureMapService.getXmlString();
        System.out.println(xml);
        // 获取地理信息服务的XML内容
        // serviceName (String): 工程名称。
        // type (int): 类型（0：所有，1：图片，2：属性，3：实体编辑，4：路径分析，5：缓冲区，6：服务）。
        // xml (String): xml内容。
        String res = conn.getServiceXml(serverName, 2, xml);
        // 解析和处理地图相关的XML数据
        MapXML mapXML = new MapXML();
        // 解析XML数据以获取实体的属性信息
        DmGetFeature feature = mapXML.dmGetFeatureInfo(res);
        // 获取实体集合
        // DmObj 类用于表示地图中每个实体的信息，包括实体号、索引号、坐标类型、坐标信息、范围、属性信息等。
        List<DmObj> map = feature.getObjset();

        List<HamletsAndRoadsInfoDto> list = new ArrayList<>();
        if (dlfxDto.getLayerName().equals("村点")) {
            for (DmObj dmObj : map) {
                HamletsAndRoadsInfoDto infoDto = new HamletsAndRoadsInfoDto();
                // 拿到点或点集
                String strPnt = dmObj.getStrPnt();
                // 处理坐标数据
                String[] s = strPnt.split(" ");
                double x = Double.parseDouble(s[0]);
                double y = Double.parseDouble(s[1]);
                DmMapPoint wgs = DmgisUtils.lbtToWgs(x, y);
                List<DmMapPoint> points = new ArrayList<>();
                points.add(wgs);
                infoDto.setDmMapPointList(Collections.singletonList(points));
                // 拿到点的信息
                String name = null;
                List<DmRcoVal> rec = dmObj.getRec();
                for (DmRcoVal dmRcoVal : rec) {
                    if (dmRcoVal.getFldName().equals("NAME")) {
                        // 拿到点信息里的村点名字
                        name = dmRcoVal.getFldVal();
                        break;
                    }
                }
                infoDto.setName(name);
                list.add(infoDto);
            }
        }else if (dlfxDto.getLayerName() == "乡村道路" || dlfxDto.getLayerName() == "高速" ||
                dlfxDto.getLayerName() == "国道" || dlfxDto.getLayerName() == "省道" ||
                dlfxDto.getLayerName() == "铁路" || dlfxDto.getLayerName() == "县道"){

            for (DmObj dmObj : map) {
                // 这里的坐标点还获取不到，后续补充
                String strPnt = dmObj.getStrPnt();
                System.err.println("strPnt : " + strPnt);
            }
            return null;
        }
        return list;
    }


    // 根据图层的类型映射类型
    private Object getLayerObject(List<DmRcoVal> rec,String layerName) throws NoSuchFieldException, InstantiationException, IllegalAccessException {
        Class objectClass = null;
        switch (layerName){
            case "村点":
                objectClass = VillagePointLayer.class;
                break;
            case "乡镇面":
                objectClass = TownshipLayer.class;
                break;
        }

        Object object = objectClass.newInstance();
        for (DmRcoVal dmRcoVal : rec) {
            Field field = objectClass.getDeclaredField(dmRcoVal.getFldName());//获取私有字段
            field.setAccessible(true);//设置权限
            field.set(object,dmRcoVal.getFldVal());
        }
        return object;
    }





    //判断水位等级
    HashMap<String, String> map = new HashMap<>();

    private ColorAndPos judgment(String stationName, double value) {
        ColorAndPos colorAndPos = new ColorAndPos();
        String red = "#FF0000";//红色
        String oranegRde = "#FF4500";//橙红色
        String orange = "#FFA500";//橙色
        String green = "#00FF00";//绿色
        String warnInfo1 = "可能性很大";
        String warnInfo2 = "可能性大";
        String warnInfo3 = "可能性较大";
        String warnInfo4 = "未达警戒值";
        map.put(warnInfo1, red);
        map.put(warnInfo2, oranegRde);
        map.put(warnInfo3, orange);
        map.put(warnInfo4, green);
        double[][] pos;
        System.err.println(stationName);
        System.err.println(value);
        System.err.println(floodedMapper);
        List<Flooded> floodeds = floodedMapper.selectList(new LambdaQueryWrapper<Flooded>()
                .eq(Flooded::getStationname, stationName));
        if (floodeds.size() == 0) {
            try {
                throw new Exception("没有相关预案信息，请先生成！！！");
            } catch (Exception e) {
                e.printStackTrace();
            }
        } else if (floodeds.size() > 0) {
            List<Date> dateList = new ArrayList<>();
            for (Flooded flooded : floodeds) {
                dateList.add(flooded.getTime());
            }
            Date nearestDate = findNearestDate(dateList);
            // 如果数据库有两个相同的最近时间这里会报异常
            Flooded flooded = floodedMapper.selectOne(new LambdaQueryWrapper<Flooded>()
                    .eq(Flooded::getStationname, stationName)
                    .eq(Flooded::getTime, nearestDate));
            System.err.println(flooded);
            String warnlevel = flooded.getWarnlevel();
            Double waterlev = flooded.getWaterlev();
            String[] split = flooded.getPos().split(",");
            pos = new double[split.length / 2][2];
            for (int i = 0; i < split.length; i += 2) {
                double x = Double.parseDouble(split[i]);
                double y = Double.parseDouble(split[i + 1]);
                pos[i / 2][0] = x;
                pos[i / 2][1] = y;
            }
            if (value > waterlev) {
                colorAndPos.setPos(pos);
                colorAndPos.setColor(map.get(warnlevel));
            } else {
                colorAndPos.setPos(pos);
                colorAndPos.setColor(green);
            }
        }
        return colorAndPos;
    }

    // 找出集合中的距离现在最近的时间
    private Date findNearestDate(List<Date> dates) {
        Date nearestDate = null;
        long currentTimeMillis = System.currentTimeMillis();

        for (Date date : dates) {
            if (nearestDate == null || Math.abs(date.getTime() - currentTimeMillis) < Math.abs(nearestDate.getTime() - currentTimeMillis)) {
                nearestDate = date;
            }
        }
        return nearestDate;
    }
}
